﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using System.Windows.Forms;
using UCL;
using UCL.Data;
using UCL.Forms;

namespace DBKit5
{
    public partial class frmModuleList : Form
    {
        // LTSF目录地址
        string strLTSFDir;

        // 是否正在编辑中
        bool isEditing = false;


        // 字段缓存数据表
        Dictionary<string, DataTable> dictDoc;

        // 表缓存数据表
        DataTable dtTables;

        // 当前编辑的数据表名称
        string tblName;

        public frmModuleList()
        {
            InitializeComponent();
            btnApply.Enabled = false;
        }

        private void frmModuleList_Load(object sender, EventArgs e)
        {
            strLTSFDir = string.Format("{0}\\ADFS\\LTSF", Application.StartupPath);
            if (!Directory.Exists(strLTSFDir)) Directory.CreateDirectory(strLTSFDir);

            cbbDbType.DataSource = new GeneralDataTypeHelper().GetDBProviderSet("General", "General");
            cbbDbType.DisplayMember = "Name";
            cbbDbType.ValueMember = "Provider";
            MenuItemEventHandler();
            this.FormLoad();
        }

        private void FormLoad()
        {
            this.FormLoad_Xml();
            this.FormLoad_LTSF();
        }

        // 加载xml中的数据
        private void FormLoad_Xml()
        {
            if (tbPath.TextLength == 0) return;
            if (!File.Exists(tbPath.Text))
            {
                MessageBox.Show("文件不存在");
                return;
            }

            // 设置数据库信息
            XElement doc = XDocument.Load(tbPath.Text).Element("db");
            cbbDbType.SelectedValue = doc.Attribute("DbProvider").GetValue();
            if (cbbDbType.SelectedIndex == -1) MessageBox.Show("未指定数据库类型");
            this.dtTables = doc.XPathSelectElements("table").ToAttributesDataTable("Name", "Alias", "Comment");
            lbTables.SetDataSource(this.dtTables, "Name", "Name");

            this.dictDoc = new Dictionary<string, DataTable>();

            // 将每个表的字段信息加载到缓存中
            foreach (XElement nTable in doc.Elements("table"))
            {
                this.dictDoc[nTable.Attribute("Name").Value] = nTable.Elements("field").ToAttributesDataTable("Name", "Type", "Length", "Default", "Key", "Null", "Extra", "Comment");
            }
        }

        // 加载指定表的信息（表信息和字段)
        private void FormLoad_Fields()
        {
            if (lbTables.SelectedIndex == -1) return;

            this.tblName = lbTables.GetSelectedValue();

            btnApply.Enabled = true;

            if (!this.dictDoc.Keys.Contains(tblName)) return;

            // 加载选中的数据表信息
            DataRow r = dtTables.Select("Name='{0}'".Fmt(tblName)).FirstOrDefault();
            tbTableName.Text = r["Name"].ToString();
            tbTableComment.Text = r["Comment"].ToString();
            tbTableAlias.Text = r["Alias"].ToString();

            // 加载选中的数据表的字段信息
            dgvFields.DataSource = this.dictDoc[tblName];
        }

        // 加载LTSF文件
        private void FormLoad_LTSF()
        {
            cbbLTSF.Items.Clear();
            foreach (string fn in Directory.GetFiles(strLTSFDir))
            {
                cbbLTSF.Items.Add(Path.GetFileNameWithoutExtension(fn));
            }
        }

        /// <summary>
        /// 更新字段到缓存中
        /// </summary>
        /// <param name="name"></param>
        /// <param name="type"></param>
        /// <param name="length"></param>
        /// <param name="defv"></param>
        /// <param name="isKey"></param>
        /// <param name="isNull"></param>
        /// <param name="extra"></param>
        /// <param name="comment"></param>
        /// <param name="oldName"></param>
        public void UpdateFieldData(string name, string type, string length, string defv, bool isKey, bool isNull, string extra, string comment, string oldName = "")
        {
            if (string.IsNullOrEmpty(tblName))
            {
                MessageBox.Show("数据表无效");
                return;
            }
            DataTable dtFields = this.dictDoc[tblName];
            if (string.IsNullOrEmpty(oldName))
            {
                // 新增字段
                // 判断是否字段重名
                if (dtFields.Select(string.Format("Name='{0}'", name)).Length > 0 && DialogResult.OK != MessageBox.Show("字段 [{0}] 已存在,是否覆盖？".Fmt(name), "提示", MessageBoxButtons.OKCancel)) return;
                dtFields.Rows.Add(name, type, length, defv, isKey ? 1 : 0, isNull ? 1 : 0, extra, comment);
            }
            else
            {
                // 编辑字段
                DataRow r = dtFields.Select("Name='{0}'".Fmt(oldName)).SingleOrDefault();
                r["Name"] = name;
                r["Type"] = type;
                r["Length"] = length;
                r["Default"] = defv;
                r["Key"] = isKey ? 1 : 0;
                r["Null"] = isNull ? 1 : 0;
                r["Extra"] = extra;
                r["Comment"] = comment;
            }
            isEditing = true;
        }

        /// <summary>
        /// 更新表数据到缓存中
        /// </summary>
        public void UpdateTableData()
        {
            if (this.dtTables == null)
            {
                MessageBox.Show("更新数据表失败[文档无效]");
                return;
            }

            bool isNewTable = dtTables.Select("Name='{0}'").Length == 0;
            DataRow rTable = isNewTable ? dtTables.NewRow() : dtTables.Select("Name='{0}'").FirstOrDefault();

            // 设置数据表属性
            rTable["Name"] = tbTableName.Text;
            rTable["Alias"] = tbTableAlias.Text;
            rTable["Comment"] = tbTableComment.Text;

            if (isNewTable) dtTables.Rows.Add(rTable);

            this.tblName = tbTableName.Text;
            this.dictDoc[tblName] = dtTables;

            isEditing = true;

        }

        // 将缓存数据更新到xml文件中
        private void SaveToXmlFile()
        {
            if (cbbDbType.SelectedItem == null)
            {
                MessageBox.Show("数据库类型未选择");
                return;
            }
            if (this.dtTables == null)
            {
                MessageBox.Show("文档无效");
                return;
            }

            XElement doc = new XElement("db");
            doc.Add(new XAttribute("Name", ""));
            doc.Add(new XAttribute("Version", DateTime.Today.ToString("yyyy-MM-dd")));
            doc.Add(new XAttribute("DbProvider", cbbDbType.GetSelectedValue()));

            XElement nTable, nField;
            DataTable dtFields;
            foreach (DataRow rTable in dtTables.Rows)
            {
                nTable = new XElement("table");
                foreach (DataColumn colTable in dtTables.Columns)
                {
                    nTable.Add(new XAttribute(colTable.ColumnName, rTable[colTable].ToString()));
                }
                dtFields = dictDoc[rTable["Name"].ToString()];
                foreach (DataRow rField in dtFields.Rows)
                {
                    nField = new XElement("field");
                    foreach (DataColumn colField in dtFields.Columns)
                    {
                        nField.Add(new XAttribute(colField.ColumnName, rField[colField].ToString()));
                    }
                    nTable.Add(nField);
                }
                doc.Add(nTable);
            }
            doc.Save(tbPath.Text);

            isEditing = false;

            MessageBox.Show("已保存到模型文件!");

            this.FormLoad_Xml();
        }

        // 重置表单信息
        private void ResetFields()
        {
            tbTableName.Clear();
            tbTableAlias.Clear();
            tbTableComment.Clear();
            tbSql.Clear();
            dgvFields.DataSource = null;
        }

        // 右键菜单事件配置
        private void MenuItemEventHandler()
        {
            cmif编辑ToolStripMenuItem.Click += new EventHandler(cmifMenuItem_Click);
            cmif删除ToolStripMenuItem.Click += new EventHandler(cmifMenuItem_Click);
            cmif刷新ToolStripMenuItem.Click += new EventHandler(cmifMenuItem_Click);
            cmif新增ToolStripMenuItem.Click += new EventHandler(cmifMenuItem_Click);
            cmif上移ToolStripMenuItem.Click += new EventHandler(cmifMenuItem_Click);
            cmif下移ToolStripMenuItem.Click += new EventHandler(cmifMenuItem_Click);

            cmit编辑ToolStripMenuItem.Click += new EventHandler(cmitMenuItem_Click);
            cmit删除ToolStripMenuItem.Click += new EventHandler(cmitMenuItem_Click);
            cmit刷新ToolStripMenuItem.Click += new EventHandler(cmitMenuItem_Click);
            cmit新增ToolStripMenuItem.Click += new EventHandler(cmitMenuItem_Click);
            cmit全选ToolStripMenuItem.Click += new EventHandler(cmitMenuItem_Click);
            cmit反选ToolStripMenuItem.Click += new EventHandler(cmitMenuItem_Click);
            cmit变量模板VToolStripMenuItem.Click += new EventHandler(cmitMenuItem_Click);
            cmit生成脚本ToolStripMenuItem.Click += new EventHandler(cmitMenuItem_Click);
        }

        // 字段右键菜单操作
        private void cmifMenuItem_Click(object s, EventArgs e)
        {
            ToolStripMenuItem mi = (ToolStripMenuItem)s;
            switch (mi.Name)
            {
                case "cmif编辑ToolStripMenuItem":
                    if (dgvFields.CurrentCell == null) return;
                    if (cbbDbType.SelectedItem == null)
                    {
                        MessageBox.Show("请指定数据库类型");
                        return;
                    }
                    Dictionary<string, object> dictField = new Dictionary<string, object>();
                    dictField["Name"] = dgvFields.GetCurrentValue("Name");
                    dictField["Type"] = dgvFields.GetCurrentValue("Type");
                    dictField["Length"] = dgvFields.GetCurrentValue("Length");
                    dictField["Null"] = dgvFields.GetCurrentValue("Null", false);
                    dictField["Key"] = dgvFields.GetCurrentValue("Key", false);
                    dictField["Default"] = dgvFields.GetCurrentValue("Default", string.Empty);
                    dictField["Extra"] = dgvFields.GetCurrentValue("Extra", string.Empty);
                    dictField["Comment"] = dgvFields.GetCurrentValue("Comment", string.Empty);
                    this.OpenDialog<frmModuleFieldEdit>(() => new frmModuleFieldEdit() { FieldData = dictField, DbProviderName = cbbDbType.GetSelectedValue() });
                    break;
                case "cmif删除ToolStripMenuItem":
                    ((DataTable)dgvFields.DataSource).Rows.RemoveAt(dgvFields.CurrentCell.OwningRow.Index);
                    isEditing = true;
                    /*nTable.XPathSelectElement(string.Format("field[@Name='{0}']", dgvFields.GetCurrentValue("Name"))).Remove();
                    doc.Save(tbPath.Text);
                    this.FormLoad_FieldsTable();
                     */
                    break;
                case "cmif刷新ToolStripMenuItem":
                    if (isEditing && DialogResult.OK != MessageBox.Show("刷新将放弃所有的内容修改，您确定要刷新吗?")) return;
                    //this.FormLoad_FieldsTable();
                    break;
                case "cmif新增ToolStripMenuItem":
                    this.OpenDialog<frmModuleFieldEdit>(() => new frmModuleFieldEdit() { DbProviderName = cbbDbType.GetSelectedValue() });
                    break;
                case "cmif上移ToolStripMenuItem":
                    if (Func_Node_MoveUp()) isEditing = true;
                    break;
                case "cmif下移ToolStripMenuItem":
                    if (Func_Node_MoveDown()) isEditing = true;
                    break;
            }
        }

        // 字段上移
        private bool Func_Node_MoveUp()
        {
            int i;
            ((DataTable)dgvFields.DataSource).MoveUp("Name='{0}'".Fmt(dgvFields.GetCurrentValue("Name")), out i);
            return i > -1;
        }

        // 字段下移
        private bool Func_Node_MoveDown()
        {
            int i;
            ((DataTable)dgvFields.DataSource).MoveDown("Name='{0}'".Fmt(dgvFields.GetCurrentValue("Name")), out i);
            return i > -1;
        }

        // 数据表右键菜单操作
        private void cmitMenuItem_Click(object s, EventArgs e)
        {
            ToolStripMenuItem mi = (ToolStripMenuItem)s;
            switch (mi.Name)
            {
                case "cmit编辑ToolStripMenuItem":
                    this.FormLoad_Fields();
                    break;
                case "cmit删除ToolStripMenuItem":
                    if (lbTables.SelectedIndex == -1) return;
                    dtTables.Rows.RemoveAt(lbTables.SelectedIndex);
                    dictDoc.Remove(lbTables.GetSelectedValue());
                    isEditing = true;
                    break;
                case "cmit刷新ToolStripMenuItem":
                    if (isEditing && DialogResult.OK != MessageBox.Show("刷新将放弃所有的内容修改，您确定要刷新吗?")) return;
                    this.FormLoad_Xml();
                    break;
                case "cmit新增ToolStripMenuItem":
                    this.ResetFields();
                    break;
                case "cmit全选ToolStripMenuItem": // 2013-9-25 by sutroon
                    lbTables.SetSelectedAll();
                    break;
                case "cmit反选ToolStripMenuItem": // 2013-9-25 by sutroon
                    lbTables.SetSelectedInverse();
                    break;
                case "cmit生成脚本ToolStripMenuItem": // 2013-9-25 by sutroon
                    if (cbbDbType.SelectedItem == null)
                    {
                        MessageBox.Show("无效的数据库类型");
                        return;
                    }
                    if (isEditing)
                    {
                        MessageBox.Show("当前内容已修改，请先点击[应用]保存数据");
                        return;
                    }
                    DatabaseProduct dbp = new GeneralDataTypeHelper().GetDatabaseProvider(cbbDbType.GetSelectedValue());
                    IDatabaseHelper idh = null;
                    switch (dbp)
                    {
                        case DatabaseProduct.SQLServer:
                            idh = new SQLServerHelper("");
                            break;
                        case DatabaseProduct.MySQL:
                            idh = new MySQLHelper("");
                            break;
                        case DatabaseProduct.SQLite:
                            idh = new SQLiteHelper("");
                            break;
                        case DatabaseProduct.Access:
                            idh = new OleDbHelper("");
                            break;
                        default:
                            return;
                    }
                    XElement doc = XDocument.Load(tbPath.Text).Element("db");
                    tbSql.Text = idh.SO_GetCreateTableStructureSqlsByXml(doc, lbTables.GetSelectedValues().ToArray());
                    tabControl1.SelectedTab = tp脚本;
                    break;
                case "cmit变量模板VToolStripMenuItem":
                    if (isEditing)
                    {
                        MessageBox.Show("当前内容已修改，请先点击[应用]保存数据");
                        return;
                    }
                    if (lbTables.SelectedItem == null) return;
                    XElement docTemp2 = XDocument.Load(tbPath.Text).Element("db");
                    this.OpenDialog<frmGenerateVarTemplate>(() => new frmGenerateVarTemplate() { TableName = lbTables.SelectedItem.ToString(), DataTable = docTemp2.XPathSelectElement("table[@Name='{0}']".Fmt(lbTables.SelectedItem)) });
                    break;
            }
        }

        // 选择模型文件
        private void btnPickFile_Click(object sender, EventArgs e)
        {
            this.ShowOpenFileDialog("Xml 模型文件(*.xml)|*.xml", (fn) => { tbPath.Text = fn; FormLoad(); });
        }

        // 确定按钮点击
        private void btnOK_Click(object sender, EventArgs e)
        {
            this.SaveToXmlFile();
            this.Close();
        }

        // 取消按钮点击
        private void btnCancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        // 应用按钮点击
        private void btnApply_Click(object sender, EventArgs e)
        {
            this.UpdateTableData();
            btnApply.Enabled = false;
        }

        // 新建模型
        private void btnNew_Click(object sender, EventArgs e)
        {
            if (cbbDbType.SelectedIndex == -1)
            {
                MessageBox.Show("请选择数据库类型");
            }
            SaveFileDialog sfd = new SaveFileDialog() { Filter = "Xml模型文件 (*.xml)|*.xml" };
            if (DialogResult.OK != sfd.ShowDialog()) return;
            File.WriteAllText(sfd.FileName, string.Format("<?xml version=\"1.0\" encoding=\"utf-8\" ?><db Name=\"{0}\" Version=\"{1}\" DbProvider=\"{2}\" Remark=\"{3}\"></db>", tbDbName.Text, tbDbVersion.Text, cbbDbType.GetSelectedValue(), tbDbRemark.Text));
            tbPath.Text = sfd.FileName;
            // 重新加载数据
            FormLoad();
            if (DialogResult.OK != MessageBox.Show("新建模型文件成功，是否打开文件目录?", "提示", MessageBoxButtons.OKCancel)) return;
            System.Diagnostics.Process.Start(Path.GetDirectoryName(sfd.FileName));
        }

        private void lbTables_DoubleClick(object sender, EventArgs e)
        {
            this.FormLoad_Fields();
        }

        // 加载LTSF文件(长期技术支持文件)
        private void lnkLoadLTSF_Click(object sender, EventArgs e)
        {
            if (cbbLTSF.SelectedItem == null) return;
            string path = string.Format("{0}\\{1}.xml", strLTSFDir, cbbLTSF.SelectedItem);
            if (!File.Exists(path))
            {
                MessageBox.Show("文件可能已删除");
                return;
            }
            tbPath.Text = path;
            FormLoad_Xml();
        }

        // 删除LTSF文件
        private void lnkDelLTSF_Click(object sender, EventArgs e)
        {
            if (cbbLTSF.SelectedItem == null) return;
            string path = string.Format("{0}\\{1}.xml", strLTSFDir, cbbLTSF.SelectedItem);
            if (!File.Exists(path)) return;
            File.Delete(path);
            FormLoad_Xml();
        }

        // 刷新LTSF文件
        private void lnkRefreshLTSF_Click(object sender, EventArgs e)
        {
            this.FormLoad_LTSF();
        }

        // 保存LTSF文件
        private void lnkSaveLTSF_Click(object sender, EventArgs e)
        {
            if (!Directory.Exists(strLTSFDir)) Directory.CreateDirectory(strLTSFDir);
            string fn = string.Format("{0}\\{1}", strLTSFDir, Path.GetFileName(tbPath.Text));
            if (File.Exists(fn))
            {
                if (DialogResult.OK != MessageBox.Show(string.Format("文件 [{0}] 已存在，您确定要覆盖已有文件吗?", Path.GetFileNameWithoutExtension(tbPath.Text)), "提示", MessageBoxButtons.OKCancel)) return;
            }
            File.Copy(tbPath.Text, fn, true);
            this.FormLoad_LTSF();
        }

        private void btnOpenFolder_Click(object sender, EventArgs e)
        {
            if (tbPath.TextLength == 0) return;
            if (File.Exists(tbPath.Text))
            {
                MessageBox.Show("文件不存在");
            }
        }
    }
}
